/*
   Copyright [2007] Ernest.Micklei @ PhilemonWorks.com

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package org.liveboardgames.common.dictionary.collections
{
	import flash.utils.Dictionary;
	import flash.utils.IDataInput;
	import flash.utils.IDataOutput;
	import flash.utils.IExternalizable;
	
	import mx.collections.ArrayCollection;
	import mx.collections.ListCollectionView;

	/**
	 * HashCollection implements a Hash in which the values are Bindable.
	 * This means that other objects can be notified when a value changes.
	 *
	 * @author Ernest.Micklei, 2007
	 */
//	[RemoteClass(alias="org.liveboardgames.common.util.IExternalMap")]
//	[RemoteClass(alias="org.liveboardgames.common.util.ExternalMap")]
	[RemoteClass(alias="org.liveboardgames.common.util.ExternalMap")]
	public class HashCollection extends ArrayCollection implements IMap, IExternalizable
	{
		public function HashCollection(source:Array = null)
		{
			super(source);
		}

		/**
		 * Use Dictionary instead of Object, as it allows to use non-String objects
		 * as keys.
		 */
		private var _keyToIndexHash:Dictionary = new Dictionary();

		[Bindable("collectionChange")]
		public function put(key:*, value:*):void
		{
			var indexOrNull:* = _keyToIndexHash[key]
			if (indexOrNull == undefined)
			{
				var index:int = this.length;
				this.addItem(value);
				_keyToIndexHash[key] = index;
				this.setItemAt(value, index);
			}
			else
			{
				this.setItemAt(value, indexOrNull as int)
			}
		}

		[Bindable("collectionChange")]
		public function getValue(key:*):*
		{
			var indexOrNull:* = _keyToIndexHash[key]
			if (indexOrNull == undefined)
			{
				// no value for key so we return null
				return null
			}
			var index:int = indexOrNull as int
			return super.getItemAt(index);
		}

		[Bindable("collectionChange")]
		public function remove(key:*):void
		{
			var indexOrNull:* = _keyToIndexHash[key];
			delete _keyToIndexHash[key];
			if (indexOrNull != undefined)
			{
				var index:int = indexOrNull as int;
				super.removeItemAt(index);
			}

		}

		[Bindable("collectionChange")]
		public function getKeys():ListCollectionView
		{
			var keys:ListCollectionView = new ArrayCollection();

			for (var key:*in _keyToIndexHash)
			{
				keys.addItem(key);
			}
			return keys;
		}

		public override function toString():String
		{
			var result:String = "";

			for (var key:*in _keyToIndexHash)
			{
				result = result + "[" + key + ";" + getValue(key) + "] ";
			}

			return result;
		}

		public override function readExternal(input:IDataInput):void
		{
			var map:Object = input.readObject();
			if (map != null)
			{
				for (var p:String in map)
				{
					this.put(p, map[p]);
					//trace("\t properties are: " + p + " with value " + map[p]);
				}
			}
		}

		public override function writeExternal(output:IDataOutput):void
		{
			throw new Error("Use toObject() instead, lest it be mapped to a PersistentMap on the server");
		}

		public function toObject():Object
		{
			var object:Object = new Object();
			for each (var key:Object in this.getKeys())
			{
				object[key] = this.getValue(key);
				//object.key = this.getValue(key);
			}
			return object;
		}
	}
}
